package com.test.scope;

import java.util.HashMap;
import java.util.Map;

/**
 * RequestScope类实现了Scope接口，用于管理请求范围内的bean实例
 * 它使用ThreadLocal来存储每个线程独有的bean实例副本，以实现线程安全
 */
public class RequestScope implements Scope{

    // 存储请求范围内的bean实例
    private static ThreadLocal<Map<String, Object>> requestScope = ThreadLocal.withInitial(HashMap::new);

    // 存储请求结束时需要执行的销毁回调
    private static ThreadLocal<Map<String, Runnable>> destructionCallbacks = ThreadLocal.withInitial(HashMap::new);

    @Override
    public Object get(String name, ObjectFactory<?> objectFactory) {
        // 获取当前线程的请求范围
        Map<String, Object> scope = requestScope.get();
        Object bean = scope.get(name);

        // 如果bean实例不存在，则通过ObjectFactory创建并放入请求范围中
        if (bean == null){
            try{
                bean = objectFactory.getObject();
                scope.put(name, bean);
            }catch (Exception e){
                // 如果创建过程中出现异常，则抛出
                throw e;
            }
        }
        return bean;
    }

    @Override
    public Object remove(String name) {
        // 从请求范围中移除指定名称的bean实例
        Map<String, Object> scope = requestScope.get();
        return scope.remove(name);
    }

    @Override
    public void registerDestructionCallback(String name, Runnable callback) {
        // 注册请求结束时需要执行的销毁回调
        Map<String, Runnable> callbacks = destructionCallbacks.get();
        callbacks.put(name, callback);
    }

    @Override
    public String getConversationId() {
        // 返回当前请求的唯一标识
        return "request-" + Thread.currentThread().getName();
    }

    public void endRequest(){
        // 请求结束时，执行所有注册的销毁回调，并清除请求范围
        Map<String, Runnable> callbacks = destructionCallbacks.get();

        for (Map.Entry<String, Runnable> entry : callbacks.entrySet()){
            try{
                // 执行销毁回调
                entry.getValue().run();
            }catch (Exception e){
                // 如果执行回调过程中出现异常，则打印堆栈跟踪
                e.printStackTrace();
            }
        }
        // 清除当前线程的请求范围和销毁回调
        requestScope.remove();
        destructionCallbacks.remove();
    }
}
